﻿using System.Collections.Generic;
using System.Reflection;
using System.Linq;

namespace WLCompiler.Helpers.SemanticAnalyze
{
    class AssemblyTable
    {
        private readonly ReferenceContainer<Function> _functions;

        private readonly ReferenceContainer<Variable> _globals;

        public AssemblyTable()
        {
            _functions = new ReferenceContainer<Function>();

//            Define basic function
//            var predefinedFucntions = new[]
//                                          {
//                                              new Function("AddToList", typeof (void), typeof(List<int>).GetMethod("Add", new [] {typeof(int)})),
//                                              new Function("RemoveFromList", typeof(void), typeof(List<int>).GetMethod("Remove", new [] {typeof(int)}))
//                                          };
//            foreach (var predefinedFucntion in predefinedFucntions)
//            {
//                _functions.Add(predefinedFucntion);
//            }

            _globals = new ReferenceContainer<Variable>();
        }

        public Function ResolveFunction(string functionId)
        {
            return _functions.Resolve(functionId);
        }

        public Variable ResolveVariable(string variableId, ReferenceContainer<Variable> locals, Function function)
        {
            foreach (var arg in function.Arguments.Where(arg => arg.Id == variableId))
            {
                return arg;
            }

            return locals.Resolve(variableId) ?? _globals.Resolve(variableId);
        }

        public Variable ResolveVariable(string variableId, ReferenceContainer<Variable> locals, Function function, ReferenceContainer<Variable> uppers)
        {
            foreach (var arg in function.Arguments.Where(arg => arg.Id == variableId))
            {
                return arg;
            }

            return locals.Resolve(variableId) ?? uppers.Resolve(variableId) ?? _globals.Resolve(variableId);
        }

        public bool AddFunction(Function function)
        {
            var defined = _functions.Resolve(function.Id);
            if (defined != null)
            {
                return false;
            }

            _functions.Add(function);
            return true;
        }

        public bool AddGlobalVariable(Variable variable)
        {
            var defined = _globals.Resolve(variable.Id);
            if (defined != null)
            {
                return false;
            }

            _globals.Add(variable);
            return true;
        }
    }
}
